package com.liveinstars.gateway.application.filter.factory;

import com.alibaba.fastjson.JSON;
import com.liveinstars.api.dto.SignDTO;
import com.onepiece.shipelves.common.Result;
import com.onepiece.shipelves.common.enums.SystemExceptionEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;


/**
 * 鉴权Filter抽象工厂
 * @author: ting
 * @date: 2019-10-23
 */
public abstract class AbstractAuthGatewayFilterFactory<C> extends AbstractGatewayFilterFactory<C> {

    private static final Logger logger = LoggerFactory.getLogger(AbstractAuthGatewayFilterFactory.class);

    public AbstractAuthGatewayFilterFactory(Class<C> configClass) {
        super(configClass);
    }

    /**
     * 鉴权流程
     * @param exchange
     * @param chain
     * @return
     */
    public Mono<Void> auth(ServerWebExchange exchange, GatewayFilterChain chain){
//        return chain.filter(exchange);
        try {
            SignDTO signDTO = this.getSign(exchange);
            if (this.validateSign(signDTO)) {
                return chain.filter(exchange);
            } else {
                exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
                return exchange.getResponse().writeWith(Flux.just(this.getBodyBuffer(exchange.getResponse(), SystemExceptionEnum.AUTH_INVALID.createResult())));
            }
        } catch (Exception e) {
            logger.error("网关鉴权异常：{}", e.getMessage(), e);
            exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
            return exchange.getResponse().writeWith(Flux.just(this.getBodyBuffer(exchange.getResponse(), SystemExceptionEnum.AUTH_ERROR.createResult())));
        }
    }

    /**
     * 获取签名实体接口 - 根据不同的鉴权模式去实现
     * @param exchange
     * @return
     */
    abstract SignDTO getSign(ServerWebExchange exchange);

    /**
     * 签名验证接口 - 根据不同的签名模式实现
     * @param sign
     * @return
     * @throws Exception
     */
    abstract boolean validateSign(SignDTO sign) throws Exception;

    /**
     * 封装返回值
     * @param response
     * @param result
     * @return
     */
    private DataBuffer getBodyBuffer(ServerHttpResponse response, Result result) {
        return response.bufferFactory().wrap(JSON.toJSONBytes(result));
    }

}
